#pragma once

#include <iostream>
#include"ContactException.h"
#include"httplib.h"
#include"contacts.pb.h"
#include"add_contact.pb.h"
#include"del_contact.pb.h"
#include"find_all_contacts.pb.h"
#include"find_one_contact.pb.h"
#include"ContactsMapper.hpp"

using namespace std;
using namespace httplib;
using namespace contacts;
using namespace add_contact;
using namespace del_contact;
using namespace find_all_contacts;
using namespace find_one_contact;

class ContactsServer
{
public:
    void add(AddRequest& request,AddResponse* response) const;

    void del(DelRequest& request,DelResponse* response) const;

    void findOne(FindOneContactRequest request, FindOneContactResponse* response) const;

    void findAll(FindAllContactsResponse* response) const;
private:
    void buildPeopleInfo(contacts::PeopleInfo* people, AddRequest& request) const;
    
    void buildFindOneContactResponse(const contacts::PeopleInfo &people,FindOneContactResponse *response) const;

    void buildFindAllContactsResponse(contacts::Contacts& contacts, FindAllContactsResponse* rsp) const;
};


static unsigned int random_char() {
        // 用于随机数引擎获得随机种子
        std::random_device rd;       
        // mt19937是c++11新特性，它是一种随机数算法，用法与rand()函数类似，但是mt19937具有速度快，周期长的特点
        // 作用是生成伪随机数
        std::mt19937 gen(rd()); 
        // 随机生成一个整数i 范围[0, 255]
        std::uniform_int_distribution<> dis(0, 255);
        return dis(gen);
    }

    // 生成 UUID （通用唯一标识符）
    static std::string generate_hex(const unsigned int len) {
        std::stringstream ss;
        // 生成 len 个16进制随机数，将其拼接而成
        for (auto i = 0; i < len; i++) {
            const auto rc = random_char();
            std::stringstream hexstream;
            hexstream << std::hex << rc;
            auto hex = hexstream.str();
            ss << (hex.length() < 2 ? '0' + hex : hex);
        }
        return ss.str();
    }

void ContactsServer::buildPeopleInfo(contacts::PeopleInfo* people, AddRequest& request) const
{
    std::string uid = generate_hex(10);
    people->set_uid(uid);
    people->set_name(request.name());
    people->set_age(request.age());
    for (auto& phone : request.phone()) {
        contacts::PeopleInfo_Phone* peo_phone = people->add_phone();
        peo_phone->set_number(phone.number());

        switch (phone.type()) {
            case AddRequest_Phone_PhoneType_M_P:
                  peo_phone->set_type(contacts::PeopleInfo_Phone_PhoneType::PeopleInfo_Phone_PhoneType_MP);
                  break;
            case AddRequest_Phone_PhoneType_TEL_P:
                  peo_phone->set_type(contacts::PeopleInfo_Phone_PhoneType::PeopleInfo_Phone_PhoneType_TEL);
                  break;
            default:
                  break;
        }
    }
}

void ContactsServer::buildFindOneContactResponse(const contacts::PeopleInfo &people,FindOneContactResponse *response) const
{
    if (nullptr == response) {
        return;
    }
    response->set_success(true);
    response->set_name(people.name());
    response->set_age(people.age());
    for (auto& phone : people.phone()) 
    {
        FindOneContactResponse_Phone* resp_phone = response->add_phone();
        resp_phone->set_number(phone.number());
    }
}

void ContactsServer::buildFindAllContactsResponse(contacts::Contacts& contacts, FindAllContactsResponse* rsp) const
{
    if (nullptr == rsp) {
        return;
    }
    
    rsp->set_success(true);
    for (auto it = contacts.contacts().cbegin(); it != contacts.contacts().cend(); ++it) 
    {
        find_all_contacts::PeopleInfo* people = rsp->add_contacts();
        people->set_uid(it->first);
        people->set_name(it->second.name());
    }
}


void ContactsServer::add(AddRequest& request,AddResponse* response) const
{
    ContactsMapper contactsMapper;

    // 先读取已存在的 contacts
    contacts::Contacts contacts;
    contactsMapper.selectContacts(&contacts);

    // 转换为存入文件的消息对象  
    google::protobuf::Map<std::string, contacts::PeopleInfo>* map_contacts = contacts.mutable_contacts();
    contacts::PeopleInfo people;
    buildPeopleInfo(&people, request);   
    map_contacts->insert({people.uid(), people});   

    // 向磁盘文件写入新的 contacts
    contactsMapper.insertContacts(contacts);
    response->set_uid(people.uid());
    response->set_success(true);

    // 打印日志
    cout << "---> (ContactsServer::add) Success to write contacts." << endl;
}

void ContactsServer::del(DelRequest& request,DelResponse* response) const
{
    ContactsMapper contactsMapper;

    // 打印日志
    cout << "---> (ContactsServer::del) DelContactRequest: uid: " << request.uid() << endl;  

    // 先读取已存在的 contacts
    contacts::Contacts contacts;
    contactsMapper.selectContacts(&contacts);

    // 不含uid直接返回
    if (contacts.contacts().find(request.uid()) == contacts.contacts().end()) {  
        cout << "---> (ContactsServer::del) not find uid: " << request.uid() << endl; 
        response->set_uid(request.uid());
        response->set_success(false);
        response->set_errmessage("not find uid");
        return;
    }
    // 删除用户
    contacts.mutable_contacts()->erase(request.uid());

    // 向磁盘文件写入新的 contacts
    contactsMapper.insertContacts(contacts);

    // 构造resp
    response->set_uid(request.uid());
    response->set_success(true);
    
    // 打印日志
    cout << "---> (ContactsServer::del) Success to del contact, uid: " << request.uid() << endl;
}

void ContactsServer::findOne(FindOneContactRequest request, FindOneContactResponse* response) const
{
    ContactsMapper contactsMapper;

    // 打印日志
    cout << "---> (ContactsServer::findOne) FindOneContactRequest: uid: " << request.uid() << endl;  

    // 获取通讯录
    contacts::Contacts contacts;
    contactsMapper.selectContacts(&contacts);

    // 转换resp消息对象
    const google::protobuf::Map<std::string, contacts::PeopleInfo>& map_contacts = contacts.contacts();
    auto it = map_contacts.find(request.uid());

    // 查找的联系人不存在
    if (it == map_contacts.end()) {
        cout << "---> (ContactsServer::findOne) not find uid: " << request.uid() << endl;
        response->set_success(false);
        response->set_errmessage("uid not exist");
        return;
    }

    // 构建resp
    buildFindOneContactResponse(it->second, response);

    // 打印日志
    cout << "---> (ContactsServer::findOne) find uid: " << request.uid() << endl;
}


void ContactsServer::findAll(FindAllContactsResponse* response) const
{
    ContactsMapper contactsMapper;
    // 打印日志
    cout << "---> (ContactsServer::findAll) " << endl;  

    // 获取通讯录
    contacts::Contacts contacts;
    contactsMapper.selectContacts(&contacts);

    // 转换resp消息对象
    buildFindAllContactsResponse(contacts, response);
}


